class Vm
  OOPS=["add", "sub", "mul", "div", "god", "jpo", "gto", "pop", "pri", "red", "hal"]

  def initialize(fname,sil=false)
    f=open(fname)
    @c=[]

    while l=f.gets
      l.strip!
      if l=~/\A[\-+]?\d+\z/
        @c << [:con,$&.to_i]
      elsif OOPS.include?(l)
        @c << [l]
      else
        raise "unknown instruction: "+l
      end
    end

    f.close
    @c.freeze

    @s=[]
    @i=0
    @step=@max=0
    @sil=sil
    @ecode=0
  end

  def run
    puts '*** START ***'
    begin
      while true
        unless @i>=0 and @i<@c.size
          raise 'cannot fetch next instruction'
        end

        case @c[@i][0]
        when :con
          con @c[@i][1]
        when 'add'
          add
        when 'sub'
          sub
        when 'mul'
          mul
        when 'div'
          div
        when 'god'
          god
        when 'jpo'
          jpo
        when 'gto'
          gto
        when 'pop'
          pop
        when 'pri'
          pri
        when 'red'
          red
        when 'hal'
          raise 'hal: stack is empty' unless @ecode=@s.pop
          break
        end

        @step+=1
      end

      puts "*** HALT#{@ecode!=0 ? " [#{@ecode}] " : " "}*** (#{@step} steps, #{@max} stacks)"
    rescue
      puts "*** ERROR [#{$!}] *** (#{@step} steps, #{@max} stacks)"
    end
  end

  private
  def con(n)
    @s << n
    @i+=1
    @max=@s.size if @s.size>@max
  end

  def pop
    unless @s.pop
      raise 'pop: stack is empty'
    end
    @i+=1
  end

  def add
    y=@s.pop
    x=@s.pop
    unless x and y
      raise 'add: stack is empty'
    end
    @s << x+y
    @i+=1
  end

  def sub
    y=@s.pop
    x=@s.pop
    unless x and y
      raise 'sub: stack is empty'
    end
    @s << x-y
    @i+=1
  end

  def mul
    y=@s.pop
    x=@s.pop
    unless x and y
      raise 'mul: stack is empty'
    end
    @s << x*y
    @i+=1
  end

  def div
    y=@s.pop
    x=@s.pop
    unless x and y
      raise 'div: stack is empty'
    end
    raise 'div: division by zero' if y==0

    q=x/y
    if q>=0 or (x%y).zero?
      @s << q
    else
      @s << q.succ
    end
    @i+=1
  end

  def pri
    if a=@s.pop
      puts a
    else
      raise 'pri: stack is empty'
    end
    @i+=1
  end

  def god
    raise 'god: stack is empty' unless n=@s.pop
    raise 'god: stack out of bounds' unless n>=0 and @s.size>n
    @s << @s[n]
    @i+=1
  end

  def gto
    raise 'gto: stack is empty' unless n=@s.pop and k=@s.pop
    raise 'gto: stack out of bounds' unless n>=0 and @s.size>n
    @s[n]=k
    @i+=1
  end

  def red
    if @sil
      t=$stdin.readline.strip
      raise 'input is not an integer!' unless t=~/\A[+\-]?[0-9]+\z/
    else
      begin
        puts 'input an integer?'
        t=$stdin.readline.strip
      end until t=~/\A[+\-]?[0-9]+\z/
      puts 'OK'
    end
    @s << t.to_i
    @i+=1
    @max=@s.size if @s.size>@max
  end

  def jpo
    raise 'jpo: stack is empty' unless n=@s.pop and k=@s.pop
    if k>0
      @i=n
    else
      @i+=1
    end
  end
end

sil=false
if $*.size==0
  fname=nil
elsif $*.size==1
  if $*[0]=='-s'
    sil=true
    fname=nil
  else
    fname=$*[0]
  end
elsif $*.size==2 and $*[0]=='-s'
  sil=true
  fname=$*[1]
elsif $*.size==2 and $*[1]=='-s'
  sil=true
  fname=$*[0]
else
  abort "usage: ruby #{$0} [-s] [code]"
end

if fname
  fname=fname+'.code' unless File.file?(fname)
else
  fname='epro.code'
end

begin
  Vm.new(fname,sil).run
rescue
  abort $!
end
